﻿
using System.Collections.Generic;
using System.Diagnostics;
using System.Net.NetworkInformation;
using System.Text;
using System.Text.RegularExpressions;
using CatEars.Text.Match;

namespace CatEars.Core.Net
{
    /// <summary>
    /// 网络状态检测
    /// </summary>
#pragma warning disable 1591
    public class NetState
    {
        /// <summary>
        /// ping的内容
        /// </summary>
        static byte[] _pingBuffer = new byte[32];

        static int _iLoadFormConfig = 0;
        public static NetState Instance { get; private set; }

        static NetState()
        {
            Instance = new NetState();
        }

        /// <summary>
        /// 初始化
        /// </summary>
        public NetState()
        {
            _ping = new Ping();
            IPInterface = new LinkedList<IPSourceDefine>();

            if (_iLoadFormConfig > 0 && Instance != null)
            {
                //从Instance中拷贝属性
                PingHost = Instance.PingHost;
                PingTimeout = Instance.PingTimeout;
                PingEachTimeout = Instance.PingEachTimeout;

                GetIPTimeout = Instance.GetIPTimeout;
                if (_iLoadFormConfig == 2)
                {
                    foreach (var entity in Instance.IPInterface)
                    {
                        IPInterface.AddLast(entity.Clone());
                    }
                }
            }
            else
            {
                PingHost = "www.baidu.com";
                PingTimeout = 10000;
                PingEachTimeout = 2500;

                GetIPTimeout = 5000;
            }
            if (IPInterface.Count == 0)
            {
                #region 默认查IP网址
                IPInterface.AddLast(new IPSourceDefine()
                {
                    ID = "ip.chinaz.com/getip.aspx",
                    Url = "http://ip.chinaz.com/getip.aspx",
                    ExInfoRegion = "address:'(?<ExInfo>.*?)'",
                });
                IPInterface.AddLast(new IPSourceDefine()
                {
                    ID = "www.ip168.com/json.do?view=myipaddress",
                    Url = "http://www.ip168.com/json.do?view=myipaddress",
                    ExInfoRegion = "来自：(?<ExInfo>.*?)</center>",
                });
                IPInterface.AddLast(new IPSourceDefine()
                {
                    ID = "1212.ip138.com/ic.asp",
                    Url = "http://1212.ip138.com/ic.asp",
                    EncodingName = "GB2312",
                    ExInfoRegion = "来自：(?<ExInfo>.*?)</center>",
                });
                IPInterface.AddLast(new IPSourceDefine()
                {
                    ID = "www.whatismyip.com.tw",
                    Url = "http://www.whatismyip.com.tw",
                });
                #endregion
            }
        }

        #region Ping

        /// <summary>
        /// Ping
        /// </summary>
        Ping _ping;

        /// <summary>
        /// ping主机
        /// </summary>
        public string PingHost { get; set; }
        /// <summary>
        /// ping超时（毫秒）
        /// </summary>
        public int PingTimeout { get; set; }
        /// <summary>
        /// 按照指定时间分多次ping，不指定则只ping一次（毫秒）
        /// </summary>
        public int PingEachTimeout { get; set; }

        /// <summary>
        /// Ping某个主机是否连通
        /// </summary>
        /// <returns>是否连通</returns>
        public bool Ping()
        {
            return Ping(PingHost, PingTimeout, PingEachTimeout);
        }
        /// <summary>
        /// Ping某个主机是否连通
        /// </summary>
        /// <param name="strHost">主机名</param>
        /// <param name="intTimeout">超时时间（毫秒）</param>
        /// <param name="intPingEachTimeout">按照指定时间分多次ping，不指定则只ping一次（毫秒）</param>
        /// <returns>是否连通</returns>
        public bool Ping(string strHost, int intTimeout, int intPingEachTimeout = 0)
        {
            int intTimeout0 = intTimeout;
            if (intTimeout0 < 1000)
            {
                //至少1秒
                intTimeout0 = 1000;
            }
            int intPingEachTimeout0 = intPingEachTimeout;
            if (intPingEachTimeout0 <= 0)
            {
                intPingEachTimeout0 = intTimeout0;
            }
            do
            {
                try
                {
                    //http://blog.csdn.net/andrew_wx/article/details/6628501
                    PingReply objPinReply = _ping.Send(
                        strHost, intPingEachTimeout0, _pingBuffer);
                    if (objPinReply.Status == IPStatus.Success)
                    {
                        return true;
                    }
                }
                catch
                {
                    //忽略异常
                }
                intTimeout0 -= intPingEachTimeout0;
            }
            while (intTimeout0 > 0);
            return false;
        }
        #endregion

        #region GetIP
        /// <summary>
        /// ping超时（毫秒）
        /// </summary>
        public int GetIPTimeout { get; set; }
        /// <summary>
        /// 缓存
        /// </summary>
        public class IPSourceDefine
        {
            /// <summary>
            /// 标识
            /// </summary>
            public string ID { get; set; }
            /// <summary>
            /// Url
            /// </summary>
            public string Url { get; set; }
            /// <summary>
            /// 返回编码
            /// </summary>
            public string EncodingName { get; set; }
            /// <summary>
            /// 获取额外信息的正则表达式
            /// </summary>
            public string ExInfoRegion { get; set; }
            /// <summary>
            /// 耗时缓存
            /// </summary>
            public long Cost { get; internal set; }

            public IPSourceDefine Clone()
            {
                return new IPSourceDefine()
                {
                    ID = this.ID,
                    Url = this.Url,
                    EncodingName = this.EncodingName,
                    ExInfoRegion = this.ExInfoRegion,
                    Cost = this.Cost
                };
            }

            public Encoding GetEncoding()
            {
                if (string.IsNullOrEmpty(EncodingName)) return null;
                else return Encoding.GetEncoding(EncodingName);
            }

            /// <summary>
            /// 解析扩展信息
            /// </summary>
            /// <param name="strContext">输入网页正文</param>
            /// <returns>扩展信息</returns>
            public string GetExInfo(string strContext)
            {
                if (!string.IsNullOrEmpty(ExInfoRegion))
                {
                    var reg = RegexCache.Instance.GetRegex(ExInfoRegion);
                    return RegexEx.ExtractValue(reg, strContext);
                }
                return null;
            }
        }
        /// <summary>
        /// 查询IP结果对象
        /// </summary>
        public class IPEntity
        {
            /// <summary>
            /// 来源ID
            /// </summary>
            public string SourceID { get; set; }
            /// <summary>
            /// IP
            /// </summary>
            public string IP { get; set; }
            /// <summary>
            /// 扩展信息
            /// </summary>
            public string ExInfo { get; set; }

            /// <summary>
            /// 重写ToString
            /// </summary>
            /// <returns>描述字符串</returns>
            public override string ToString()
            {
                if (string.IsNullOrEmpty(IP))
                {
                    return "";
                }
                string strResult = IP;
                if (!string.IsNullOrEmpty(ExInfo))
                {
                    strResult += "[" + ExInfo + "]";
                }
                if (!string.IsNullOrEmpty(SourceID))
                {
                    strResult += "(" + SourceID + ")";
                }
                return strResult;
            }
        }
        /// <summary>
        /// 获取IP的接口(不能重复)
        /// </summary>
        public LinkedList<IPSourceDefine> IPInterface { get; private set; }

        /// <summary>
        /// 获取当前互联网IP
        /// </summary>
        /// <returns>互联网IP</returns>
        public string GetIP()
        {
            if (IPInterface == null || IPInterface.Count == 0)
            {
                return null;
            }
            Stopwatch sth = new Stopwatch();
            string strFirstUrl = null;
            while (IPInterface.First != null)
            {
                var node = IPInterface.First;
                IPSourceDefine url = node.Value;
                string strUrl = url.Url;
                if (string.IsNullOrEmpty(strUrl))
                {
                    IPInterface.RemoveFirst();
                    continue;
                }
                if (strFirstUrl == null)
                {
                    strFirstUrl = strUrl;
                }
                else if (strFirstUrl == strUrl)
                {
                    break;
                }
                try
                {
                    var request = HttpRequestEx.CreateHttpRequest(strUrl, "Get", GetIPTimeout);
                    sth.Restart();
                    string strResult = HttpRequestEx.SGetContext(request, GetIPTimeout, url.GetEncoding());
                    sth.Stop();
                    url.Cost = sth.ElapsedMilliseconds;
                    UpdateCostList(node, strUrl, url);

                    Regex reg = RegexCache.Instance.GetRegex(@"((?:(?:25[0-5]|2[0-4]\d|((1\d{2})|([1-9]?\d)))\.){3}(?:25[0-5]|2[0-4]\d|((1\d{2})|([1-9]?\d))))");
                    var match = reg.Match(strResult);
                    if (match.Success)
                    {
                        return match.Value;
                    }
                    else
                    {
                        //返回的结果中无IP
                        url.Cost = long.MaxValue;
                        if (IPInterface.Count > 1)
                        {
                            IPInterface.AddLast(url);
                            IPInterface.RemoveFirst();
                        }
                    }
                }
                catch
                {
                    //获取IP出错
                    url.Cost = long.MaxValue;
                    if (IPInterface.Count > 1)
                    {
                        IPInterface.AddLast(url);
                        IPInterface.RemoveFirst();
                    }
                }
            }
            return null;
        }

        /// <summary>
        /// 获取当前互联网IP
        /// </summary>
        /// <returns>互联网IP</returns>
        public IPEntity GetIPEntity()
        {
            if (IPInterface == null || IPInterface.Count == 0)
            {
                return null;
            }
            Stopwatch sth = new Stopwatch();
            string strFirstUrl = null;
            while (IPInterface.First != null)
            {
                var node = IPInterface.First;
                IPSourceDefine url = node.Value;
                string strUrl = url.Url;
                if (string.IsNullOrEmpty(strUrl))
                {
                    IPInterface.RemoveFirst();
                    continue;
                }
                if (strFirstUrl == null)
                {
                    strFirstUrl = strUrl;
                }
                else if (strFirstUrl == strUrl)
                {
                    break;
                }
                try
                {
                    var request = HttpRequestEx.CreateHttpRequest(strUrl, "Get", GetIPTimeout);
                    sth.Restart();
                    string strResult = HttpRequestEx.SGetContext(request, GetIPTimeout, url.GetEncoding());
                    sth.Stop();
                    url.Cost = sth.ElapsedMilliseconds;
                    UpdateCostList(node, strUrl, url);

                    Regex reg = RegexCache.Instance.GetRegex(@"((?:(?:25[0-5]|2[0-4]\d|((1\d{2})|([1-9]?\d)))\.){3}(?:25[0-5]|2[0-4]\d|((1\d{2})|([1-9]?\d))))");
                    var match = reg.Match(strResult);
                    if (match.Success)
                    {
                        IPEntity result = new IPEntity()
                        {
                            SourceID = url.ID,
                            IP = match.Value,
                            ExInfo = url.GetExInfo(strResult),
                        };
                        return result;
                    }
                    else
                    {
                        //返回的结果中无IP
                        url.Cost = long.MaxValue;
                        if (IPInterface.Count > 1)
                        {
                            IPInterface.AddLast(url);
                            IPInterface.RemoveFirst();
                        }
                    }
                }
                catch
                {
                    //获取IP出错
                    url.Cost = long.MaxValue;
                    if (IPInterface.Count > 1)
                    {
                        IPInterface.AddLast(url);
                        IPInterface.RemoveFirst();
                    }
                }
            }
            return null;
        }

        /// <summary>
        /// 更新查IP耗时
        /// </summary>
        /// <param name="node"></param>
        /// <param name="strUrl"></param>
        /// <param name="url"></param>
        private void UpdateCostList(
            LinkedListNode<IPSourceDefine> node,
            string strUrl,
            IPSourceDefine url)
        {
            for (var node2 = node.Next; node2 != null; node2 = node2.Next)
            {
                IPSourceDefine url2 = node.Value;
                string strUrl2 = url2.Url;
                if (url.Cost < url2.Cost)
                {
                    if (node.Next != node2)
                    {
                        IPInterface.AddBefore(node2, url);
                        IPInterface.RemoveFirst();
                        return;
                    }
                }
            }
            IPInterface.AddLast(url);
            IPInterface.RemoveFirst();
        }
        #endregion
    }
}
